/** \file gr_algorithms.h */

#pragma once


#include<map>
#include<functional>
#include<utility>
#include<iterator>

namespace gr {

/** Unsafe version of std::copy */
template<class II, class OI>
void unsafeCopy(II begin, II end, OI out)
{
    while(begin != end) *out++ = *begin++;
}

/** Transfer contents of container T to container V through MAP if PRED-predicate is true for element. */
template<class T, class V, class PRED, class MAP>
void filter(T& in, V& out, PRED pred, MAP map)
{
    auto insert = std::inserter(out);
    for(typename T::iterator i = in.begin(); i != in.end(); ++i)
    {
        if(pred(*i))
        {
            *insert = map(*i);
            ++insert;
        }
    }
}

template<class T, class ITER>
void forEach(T& data, ITER fun)
{
    std::for_each(data.begin(), data.end(), fun);
}

template<class M, class ITER>
void forEachValue(M& map, ITER iter)
{
    for(auto i = map.begin(); i != map.end(); ++i)
        iter(i->second);
}

template<class M, class ITER>
void forEachKey(M& map, ITER iter)
{
    for(auto i = map.begin(); i != map.end(); ++i)
        iter(i->first);
}

template<class M, class ITER>
void forEachPair(M& map, ITER iter)
{
    for(auto i = map.begin(); i != map.end(); ++i)
        iter(i->first, i->second);
}

template<class M, class KEY>
bool hasKey(M& map, KEY key)
{
    return map.count(key) > 0;
}

/** Try to find value matching key. */ 
template<class M>
typename M::mapped_type* tryGetValue(M& map, typename M::key_type& key)
{
    typename M::mapped_type* result = nullptr;
    if(map.count(key) > 0)
    {
        result = &map[key];
    }
    return result;
}

template<class T>
struct GenericResult{
    T value;
    bool isValid;
    T& operator*(){return value;}
    T& operator->(){return value;}
};

template<class T> GenericResult<T> genericResult(T value, bool valid){
    GenericResult<T> g =  {value, valid};
    return g;
}

template<class T>
bool operator==(const GenericResult<T> result, bool b){return result.isValid = b;}
template<class T>
bool isValid(const GenericResult<T>& result){return result.isValid;}

/** Try to find the first key,value pair for witch the ITER function returns true.*/ 
template<class K, class V>
GenericResult<typename std::map<K, V>::iterator> tryGetPair(std::map<K, V>& map, std::function<bool(typename std::map<K, V>::iterator)> iter)
{
    // vc2010 could not infer types for std::find_if
    auto end = map.end();
    auto i = map.begin();
    for(;i != end; ++i)
    {
        if(iter(i)) break;
    } 
    return genericResult(i, i != end);
}


/** Try to find a key (any key) matching a value. */ 
template<class K, class V>
K* tryGetKey(std::map<K, V>& map, V& value)
{
    K* key = nullptr;
    auto end = map.end();
    auto get = [&value](std::pair<K,V>& pair)->bool{return pair.second == value;};
    auto ipair = std::find_if(map.begin(), end, get);
    if(ipair != end)
    {
        key = &(ipair->first);
    }
    return key;
}


}